热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

解析链接脚本与可执行文件的关系

本文详细探讨了链接脚本和可执行文件的基本概念及其在嵌入式系统中的应用,特别是S32K144芯片的具体实现。

本文由编程笔记小编整理,旨在介绍链接脚本和可执行文件的相关知识,帮助读者深入理解这些概念。


基本概念

以下是关于链接器、链接脚本和可执行程序的重要概念:

链接器(Linker)

链接器是一个程序,其主要功能是将多个目标文件(包括标准库函数的目标文件)的代码段、数据段及符号表等内容整合成一个符合ELF或EXE等格式的可执行二进制文件。

链接脚本

链接器在链接过程中需要使用链接脚本。如果没有通过“-T”参数指定链接脚本,链接器会使用默认的内部脚本。链接脚本的主要作用是将输入文件的段按指定的地址空间布局合并到输出文件的段中,使输出文件具备可执行性。

可执行程序

任何可执行程序,无论是Windows的.exe文件还是Linux的.elf文件,都由代码段、数据段、未初始化的数据段等部分组成。

段(Section)

每个输出段有两个地址:虚拟地址(Virtual Memory Address, VMA):运行时的地址;加载地址(Load Memory Address, LMA):加载时的地址。如果没有通过“AT”指定LMA,则LMA等于VMA。在嵌入式系统中,加载地址和运行地址常常不同,例如,程序可能存储在Flash中,但在运行时复制到RAM中。


分析S32K144的工程

我们以S32K1xx_flash_debug.ld为例,解析其内存映射和链接脚本的细节。

1. 内存映射(Memory Map)是处理器的存储布局,描述了CPU指令集可以直接寻址的外部存储空间。这些存储器可以是Flash、NAND Flash、SRAM、DDR等。

/* Specify the memory areas */
MEMORY
  /* Flash */
  m_interrupts          (RX)  : ORIGIN = 0x00000000, LENGTH = 0x00000400
  m_flash_config        (RX)  : ORIGIN = 0x00000400, LENGTH = 0x00000010
  m_text                (RX)  : ORIGIN = 0x00000410, LENGTH = 0x0007FBF0
  /* SRAM_L */
  m_data                (RW)  : ORIGIN = 0x1FFF8000, LENGTH = 0x00008000
  /* SRAM_U */
  m_data_2              (RW)  : ORIGIN = 0x20000000, LENGTH = 0x00007000

2. 目标可执行文件由输入文件的各个段填充,具体的填充规则和地址定义在链接脚本中。

中断向量和OS的异常向量表存储在m_interrupts段中,该段位于地址空间的ORIGIN = 0x00000000, LENGTH = 0x00000400。

.interrupts :
  
  __VECTOR_TABLE = .;
  . = ALIGN(4);
  "*(.isr_vector)"
  "*(Os_ExceptionVectors)" /* Startup code */
  . = ALIGN(4);
  > m_interrupts

代码段(.code)的虚拟地址(运行时地址)位于m_text (RX) : ORIGIN = 0x00000410, LENGTH = 0x0007FBF0,数据段的虚拟地址(运行时地址)位于m_data,bss段的虚拟地址(运行时地址)位于m_data_2。注意,段的虚拟地址和存储地址是不同的。

3. 链接脚本中的地址信息会被程序引用,因此链接脚本也是程序的一部分,可以看作是一个头文件。

__etext = .;    /* Define a global symbol at end of code. */
  __DATA_ROM = .; /* Symbol is used by startup for data initialization. */
  .data : AT(__DATA_ROM)
  
  . = ALIGN(4);
  __DATA_RAM = .;
  __data_start__ = .;      /* Create a global symbol at data start. */
  "*(.data)"               /* .data sections */
  "*(.data*)"              /* .data* sections */
  "*(.os_data)"
  "*(.mcal_data)"
  "*(.jcr*)"
  . = ALIGN(4);
  __data_end__ = .;        /* Define a global symbol at data end. */
  > m_data

虚拟地址是程序运行时的地址,加载地址是程序存储时的地址或加载源地址。

数据段定义了两个宏地址,这些宏会被C代码引用。

__DATA_ROM是紧接在代码段之后的一个地址,AT(__DATA_ROM)表示将.data段的加载地址设置为__DATA_ROM。

在startup_init_bss.c中引用了这个地址:

void init_data_bss(void)
data_rom       = (uint8_t *)__DATA_ROM;
/* Copy initialized data from ROM to RAM */
    while (data_rom_end != data_rom)
    
        *data_ram = *data_rom;
        data_ram++;
        data_rom++;
    

在startup.s中使用init_data_bss,将.data段从加载地址拷贝到运行地址(实际上是将数据从Flash拷贝到SRAM)。即使不拷贝,只要CPU可以寻址,程序也能执行,因为Flash和SRAM都在地址空间内。

; Init .data and .bss sections
    LDR     R0,=init_data_bss
    BLX     R0
    ;cpsie   i              ; Unmask interrupts
    BL      main

从规格书中查找memory map:

总结:

1. 可执行程序由数据段、代码段、bss段等组成。

2. 每个段对应两个地址:虚拟地址(运行地址)和加载地址(存储地址),这些地址都在CPU可寻址的地址空间内。

3. 链接脚本中的地址信息会被C代码引用,链接脚本可以视为程序的一部分(类似头文件)。

4. CPU的memory map对应的存储器可以是Flash、SRAM、DDR等。如果加载地址和运行地址不同,程序在启动时(如在startup.s中)需要将加载地址的内容复制到运行地址。加载地址和运行地址由程序员根据存储器特性自定义。


推荐阅读
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • 本文详细介绍如何使用Python进行配置文件的读写操作,涵盖常见的配置文件格式(如INI、JSON、TOML和YAML),并提供具体的代码示例。 ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 本文介绍了一款用于自动化部署 Linux 服务的 Bash 脚本。该脚本不仅涵盖了基本的文件复制和目录创建,还处理了系统服务的配置和启动,确保在多种 Linux 发行版上都能顺利运行。 ... [详细]
  • 本文详细介绍了如何在 Spring Boot 应用中通过 @PropertySource 注解读取非默认配置文件,包括配置文件的创建、映射类的设计以及确保 Spring 容器能够正确加载这些配置的方法。 ... [详细]
  • 资源推荐 | TensorFlow官方中文教程助力英语非母语者学习
    来源:机器之心。本文详细介绍了TensorFlow官方提供的中文版教程和指南,帮助开发者更好地理解和应用这一强大的开源机器学习平台。 ... [详细]
  • 本文介绍如何使用Objective-C结合dispatch库进行并发编程,以提高素数计数任务的效率。通过对比纯C代码与引入并发机制后的代码,展示dispatch库的强大功能。 ... [详细]
  • python的交互模式怎么输出名文汉字[python常见问题]
    在命令行模式下敲命令python,就看到类似如下的一堆文本输出,然后就进入到Python交互模式,它的提示符是>>>,此时我们可以使用print() ... [详细]
  • CentOS7源码编译安装MySQL5.6
    2019独角兽企业重金招聘Python工程师标准一、先在cmake官网下个最新的cmake源码包cmake官网:https:www.cmake.org如此时最新 ... [详细]
  • 本文介绍了如何使用JQuery实现省市二级联动和表单验证。首先,通过change事件监听用户选择的省份,并动态加载对应的城市列表。其次,详细讲解了使用Validation插件进行表单验证的方法,包括内置规则、自定义规则及实时验证功能。 ... [详细]
  • 数据库内核开发入门 | 搭建研发环境的初步指南
    本课程将带你从零开始,逐步掌握数据库内核开发的基础知识和实践技能,重点介绍如何搭建OceanBase的开发环境。 ... [详细]
  • 前言--页数多了以后需要指定到某一页(只做了功能,样式没有细调)html ... [详细]
  • 本文详细分析了Hive在启动过程中遇到的权限拒绝错误,并提供了多种解决方案,包括调整文件权限、用户组设置以及环境变量配置等。 ... [详细]
author-avatar
UNESCO媒介与女性教席走_890
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有